# coding=utf-8

import os
from string import Template
from typing import List
from parse.sdb_parser import ECU

from utils.templete_file import TempleteFile
from parse.parse_types import  Module
from utils.util import writeFile

vaildate_h=Template("""
#pragma once
#include <vector>
#include <cstdint>
#include "vp/SignalServiceId.h"
namespace ecarx::transfer::validate {
    struct ValidOperationArray
    {
        int len;
        uint16_t * oper_ids;
    };

    const uint16_t getAllServiceIds[]={
${getAllList}
    };

    const uint16_t getReadyServiceIds[] = {
            EcarXSignalServiceID::serviceID_CARCONFIG,
            EcarXSignalServiceID::serviceID_CARCONFIGTHOUSAND,
            EcarXSignalServiceID::serviceID_CLIMATE,
    };

    const ValidOperationArray getValidOperation(const int);

    bool availableServiceID(const int);
} 
""")

vaildate_cpp = Template("""
#include "validate.h"
#include "vp/SignalServiceId.h"

${defines}

namespace ecarx::transfer::validate {
    const ValidOperationArray getValidOperation(const int serviceId){
        ValidOperationArray ret;
        switch (serviceId) {
${cases}
        }
        return ret;
    }

    bool availableServiceID(const int serviceId){
        return ${condition};
    }
}
""")

case_tempelet = Template(
"""            case ${id}:{
                ret.len=${len};
                ret.oper_ids = ${op_id};
                break;
            }
""")

class Case(TempleteFile):

    def __init__(self, id) -> None:
        self.id = id

    def len(self, len: str):
        self.len= len

    def op_id(self,opid:str):
        self.op_id=opid
    

    def toStr(self) -> str:
        return case_tempelet.substitute(id=self.id, len=self.len,op_id=self.op_id)


def gen_Validate(ecus:List[ECU],modules:List[Module],outDir:str):
    # 收集每个serviceid对应的oper_id
    getAllServiceList=[
        "EcarXSignalServiceID::serviceID_CARCONFIG",
        "EcarXSignalServiceID::serviceID_CARCONFIGTHOUSAND",
        "EcarXSignalServiceID::serviceID_RX1",
        "EcarXSignalServiceID::serviceID_RX2",
    ]
    defines=[]
    cases=[]
    conditions=[]
    defines.append("static uint16_t RX1Oper[]={{{0}}};".format(",".join(["0xa11,1001"])))
    conditions.append("serviceId == EcarXSignalServiceID::serviceID_RX1")
    rx1_case = Case("EcarXSignalServiceID::serviceID_RX1")
    rx1_case.len("2")
    rx1_case.op_id("RX1Oper")
    cases.append(rx1_case)

    defines.append("static uint16_t RX2Oper[]={{{0}}};".format(",".join(["0xa11,1002"])))
    conditions.append("serviceId == EcarXSignalServiceID::serviceID_RX2")
    rx2_case = Case("EcarXSignalServiceID::serviceID_RX2")
    rx2_case.len("2")
    rx2_case.op_id("RX2Oper")
    cases.append(rx2_case)
    
    for ecu in ecus:
        (service_id_name,service_id_value) = ecu.getServiceId()
        conditions.append("serviceId == {}".format("EcarXSignalServiceID::{0}".format(service_id_name)))
        op_ids=[]
        case = Case("EcarXSignalServiceID::{0}".format(service_id_name))
        
        if ecu.hasReadSignals():
            op_ids.append("0xa11")
            op_ids.append("{0}".format(hex(ecu.rxPackage.opcode)))

        for tx in ecu.txSignals:
            op_ids.append(str(tx.opcode))

        case.len("{}".format(len(op_ids)))
        case.op_id("{0}Oper".format(ecu.name.upper()))
        cases.append(case)
        defines.append("static uint16_t {0}Oper[]={{{1}}};".format(ecu.name.upper(),",".join(op_ids)))
    
    for module in modules:
        op_ids=[]
        conditions.append("serviceId == {}".format("EcarXSignalServiceID::serviceID_{0}".format(module.name.upper())))
        case = Case("EcarXSignalServiceID::serviceID_{0}".format(module.name.upper()))

        if len(module.pa_apis) >0:
            op_ids.append(module.pa_apis[0].op_id)
        for cb in module.cb_apis:
            op_ids.append(cb.op_id)
            if cb.op_id == "2577" or cb.op_id.lower() =="0xa11":
                getAllServiceList.append("EcarXSignalServiceID::serviceID_{0}".format(module.name.upper()))

        case.len("{}".format(len(op_ids)))
        case.op_id("{0}Oper".format(module.name.upper()))
        cases.append(case)
        defines.append("static uint16_t {0}Oper[]={{{1}}};".format(module.name.upper(),",".join(op_ids)))
    
    writeFile(os.path.join(outDir,"src"),"validate.h",lambda f:f.write(vaildate_h.substitute(
        getAllList=",\n".join(getAllServiceList)
    )))
    writeFile(os.path.join(outDir,"src"),"validate.cpp",lambda f:
        f.write(vaildate_cpp.substitute(
            defines="\n".join(defines),
            cases="".join([case.toStr() for case in cases]),
            condition=" ||\n\t".expandtabs(15).join(conditions)
        )))




    
